/*
 * FILE: hm.c
 *
 * health monitor management functions
 *
 * www.prtos.org
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "common.h"
#include "prtos_conf.h"

#define FILL_TAB(x) [x] = #x

char *hm_log[2] = {
    FILL_TAB(PRTOS_HM_LOG_DISABLED),
    FILL_TAB(PRTOS_HM_LOG_ENABLED),
};

char *hm_actions[PRTOS_HM_MAX_ACTIONS] = {
    FILL_TAB(PRTOS_HM_AC_IGNORE),
    FILL_TAB(PRTOS_HM_AC_SHUTDOWN),
    FILL_TAB(PRTOS_HM_AC_PARTITION_COLD_RESET),
    FILL_TAB(PRTOS_HM_AC_PARTITION_WARM_RESET),
    FILL_TAB(PRTOS_HM_AC_HYPERVISOR_COLD_RESET),
    FILL_TAB(PRTOS_HM_AC_HYPERVISOR_WARM_RESET),
    FILL_TAB(PRTOS_HM_AC_SUSPEND),
    FILL_TAB(PRTOS_HM_AC_PARTITION_HALT),
    FILL_TAB(PRTOS_HM_AC_HYPERVISOR_HALT),
    FILL_TAB(PRTOS_HM_AC_PROPAGATE),
    FILL_TAB(PRTOS_HM_AC_SWITCH_TO_MAINTENANCE),
};

char *hm_events[PRTOS_HM_MAX_EVENTS] = {
    FILL_TAB(PRTOS_HM_EV_FATAL_ERROR),
    FILL_TAB(PRTOS_HM_EV_SYSTEM_ERROR),
    FILL_TAB(PRTOS_HM_EV_PARTITION_ERROR),
    FILL_TAB(PRTOS_HM_EV_FP_ERROR),
    FILL_TAB(PRTOS_HM_EV_MEM_PROTECTION),
    FILL_TAB(PRTOS_HM_EV_UNEXPECTED_TRAP),

#ifdef CONFIG_x86
    FILL_TAB(PRTOS_HM_EV_X86_DIVIDE_ERROR),
    FILL_TAB(PRTOS_HM_EV_X86_DEBUG),
    FILL_TAB(PRTOS_HM_EV_X86_NMI_INTERRUPT),
    FILL_TAB(PRTOS_HM_EV_X86_BREAKPOINT),
    FILL_TAB(PRTOS_HM_EV_X86_OVERFLOW),
    FILL_TAB(PRTOS_HM_EV_X86_BOUND_RANGE_EXCEEDED),
    FILL_TAB(PRTOS_HM_EV_X86_INVALID_OPCODE),
    FILL_TAB(PRTOS_HM_EV_X86_DEVICE_NOT_AVAILABLE),
    FILL_TAB(PRTOS_HM_EV_X86_DOUBLE_FAULT),
    FILL_TAB(PRTOS_HM_EV_X86_COPROCESSOR_SEGMENT_OVERRUN),
    FILL_TAB(PRTOS_HM_EV_X86_INVALID_TSS),
    FILL_TAB(PRTOS_HM_EV_X86_SEGMENT_NOT_PRESENT),
    FILL_TAB(PRTOS_HM_EV_X86_STACK_FAULT),
    FILL_TAB(PRTOS_HM_EV_X86_GENERAL_PROTECTION),
    FILL_TAB(PRTOS_HM_EV_X86_PAGE_FAULT),
    FILL_TAB(PRTOS_HM_EV_X86_X87_FPU_ERROR),
    FILL_TAB(PRTOS_HM_EV_X86_ALIGNMENT_CHECK),
    FILL_TAB(PRTOS_HM_EV_X86_MACHINE_CHECK),
    FILL_TAB(PRTOS_HM_EV_X86_SIMD_FLOATING_POINT),
#endif
};

prtos_u32_t to_hm_action(char *s, int line) {
    int e;
    for (e = 0; e < PRTOS_HM_MAX_ACTIONS; e++)
        if (hm_actions[e] && !strcmp(s, hm_actions[e])) return e;

    line_error(line, "Expected a valid Health Monitor action");
    return 0;
}

prtos_u32_t to_hm_event(char *s, int line) {
    int e;
    for (e = 0; e < PRTOS_HM_MAX_EVENTS; e++)
        if (hm_events[e] && !strcmp(s, hm_events[e])) return e;

    line_error(line, "Expected a valid Health Monitor event");
    return 0;
}

#define TOBIT(x) (1 << x)

static prtos_u32_t hm_partition_events_and_actions[PRTOS_HM_MAX_EVENTS] = {
    [PRTOS_HM_EV_FATAL_ERROR] = TOBIT(PRTOS_HM_AC_PARTITION_HALT) | TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT),  // CANNOT BE RAISED

    [PRTOS_HM_EV_SYSTEM_ERROR] = TOBIT(PRTOS_HM_AC_SHUTDOWN) | TOBIT(PRTOS_HM_AC_PARTITION_COLD_RESET) | TOBIT(PRTOS_HM_AC_PARTITION_WARM_RESET) |
                                 TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_SUSPEND) |
                                 TOBIT(PRTOS_HM_AC_PARTITION_HALT) | TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_SWITCH_TO_MAINTENANCE),

    [PRTOS_HM_EV_PARTITION_ERROR] = TOBIT(PRTOS_HM_AC_IGNORE) | TOBIT(PRTOS_HM_AC_SHUTDOWN) | TOBIT(PRTOS_HM_AC_PARTITION_COLD_RESET) |
                                    TOBIT(PRTOS_HM_AC_PARTITION_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) |
                                    TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_SUSPEND) | TOBIT(PRTOS_HM_AC_PARTITION_HALT) |
                                    TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_SWITCH_TO_MAINTENANCE),

    [PRTOS_HM_EV_FP_ERROR] = TOBIT(PRTOS_HM_AC_SHUTDOWN) | TOBIT(PRTOS_HM_AC_PARTITION_COLD_RESET) | TOBIT(PRTOS_HM_AC_PARTITION_WARM_RESET) |
                             TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_SUSPEND) |
                             TOBIT(PRTOS_HM_AC_PARTITION_HALT) | TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_SWITCH_TO_MAINTENANCE),

    [PRTOS_HM_EV_MEM_PROTECTION] = TOBIT(PRTOS_HM_AC_SHUTDOWN) | TOBIT(PRTOS_HM_AC_PARTITION_COLD_RESET) | TOBIT(PRTOS_HM_AC_PARTITION_WARM_RESET) |
                                   TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_SUSPEND) |
                                   TOBIT(PRTOS_HM_AC_PARTITION_HALT) | TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_SWITCH_TO_MAINTENANCE),

    [PRTOS_HM_EV_UNEXPECTED_TRAP] = TOBIT(PRTOS_HM_AC_IGNORE) | TOBIT(PRTOS_HM_AC_SHUTDOWN) | TOBIT(PRTOS_HM_AC_PARTITION_COLD_RESET) |
                                    TOBIT(PRTOS_HM_AC_PARTITION_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) |
                                    TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_SUSPEND) | TOBIT(PRTOS_HM_AC_PARTITION_HALT) |
                                    TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_SWITCH_TO_MAINTENANCE),

#ifdef CONFIG_x86
    [PRTOS_HM_EV_X86_DIVIDE_ERROR] = TOBIT(PRTOS_HM_AC_IGNORE) | TOBIT(PRTOS_HM_AC_SHUTDOWN) | TOBIT(PRTOS_HM_AC_PARTITION_COLD_RESET) |
                                     TOBIT(PRTOS_HM_AC_PARTITION_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) |
                                     TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_SUSPEND) | TOBIT(PRTOS_HM_AC_PARTITION_HALT) |
                                     TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE) | TOBIT(PRTOS_HM_AC_SWITCH_TO_MAINTENANCE),

    [PRTOS_HM_EV_X86_DEBUG] = TOBIT(PRTOS_HM_AC_IGNORE) | TOBIT(PRTOS_HM_AC_SHUTDOWN) | TOBIT(PRTOS_HM_AC_PARTITION_COLD_RESET) |
                              TOBIT(PRTOS_HM_AC_PARTITION_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) |
                              TOBIT(PRTOS_HM_AC_SUSPEND) | TOBIT(PRTOS_HM_AC_PARTITION_HALT) | TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) |
                              TOBIT(PRTOS_HM_AC_PROPAGATE) | TOBIT(PRTOS_HM_AC_SWITCH_TO_MAINTENANCE),

    [PRTOS_HM_EV_X86_NMI_INTERRUPT] = TOBIT(PRTOS_HM_AC_IGNORE) | TOBIT(PRTOS_HM_AC_SHUTDOWN) | TOBIT(PRTOS_HM_AC_PARTITION_COLD_RESET) |
                                      TOBIT(PRTOS_HM_AC_PARTITION_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) |
                                      TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_SUSPEND) | TOBIT(PRTOS_HM_AC_PARTITION_HALT) |
                                      TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE) | TOBIT(PRTOS_HM_AC_SWITCH_TO_MAINTENANCE),

    [PRTOS_HM_EV_X86_BREAKPOINT] = TOBIT(PRTOS_HM_AC_IGNORE) | TOBIT(PRTOS_HM_AC_SHUTDOWN) | TOBIT(PRTOS_HM_AC_PARTITION_COLD_RESET) |
                                   TOBIT(PRTOS_HM_AC_PARTITION_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) |
                                   TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_SUSPEND) | TOBIT(PRTOS_HM_AC_PARTITION_HALT) |
                                   TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE) | TOBIT(PRTOS_HM_AC_SWITCH_TO_MAINTENANCE),

    [PRTOS_HM_EV_X86_OVERFLOW] = TOBIT(PRTOS_HM_AC_IGNORE) | TOBIT(PRTOS_HM_AC_SHUTDOWN) | TOBIT(PRTOS_HM_AC_PARTITION_COLD_RESET) |
                                 TOBIT(PRTOS_HM_AC_PARTITION_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) |
                                 TOBIT(PRTOS_HM_AC_SUSPEND) | TOBIT(PRTOS_HM_AC_PARTITION_HALT) | TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) |
                                 TOBIT(PRTOS_HM_AC_PROPAGATE) | TOBIT(PRTOS_HM_AC_SWITCH_TO_MAINTENANCE),

    [PRTOS_HM_EV_X86_BOUND_RANGE_EXCEEDED] = TOBIT(PRTOS_HM_AC_IGNORE) | TOBIT(PRTOS_HM_AC_SHUTDOWN) | TOBIT(PRTOS_HM_AC_PARTITION_COLD_RESET) |
                                             TOBIT(PRTOS_HM_AC_PARTITION_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) |
                                             TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_SUSPEND) | TOBIT(PRTOS_HM_AC_PARTITION_HALT) |
                                             TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE) | TOBIT(PRTOS_HM_AC_SWITCH_TO_MAINTENANCE),

    [PRTOS_HM_EV_X86_INVALID_OPCODE] = TOBIT(PRTOS_HM_AC_IGNORE) | TOBIT(PRTOS_HM_AC_SHUTDOWN) | TOBIT(PRTOS_HM_AC_PARTITION_COLD_RESET) |
                                       TOBIT(PRTOS_HM_AC_PARTITION_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) |
                                       TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_SUSPEND) | TOBIT(PRTOS_HM_AC_PARTITION_HALT) |
                                       TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE) | TOBIT(PRTOS_HM_AC_SWITCH_TO_MAINTENANCE),

    [PRTOS_HM_EV_X86_DEVICE_NOT_AVAILABLE] = TOBIT(PRTOS_HM_AC_IGNORE) | TOBIT(PRTOS_HM_AC_SHUTDOWN) | TOBIT(PRTOS_HM_AC_PARTITION_COLD_RESET) |
                                             TOBIT(PRTOS_HM_AC_PARTITION_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) |
                                             TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_SUSPEND) | TOBIT(PRTOS_HM_AC_PARTITION_HALT) |
                                             TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE) | TOBIT(PRTOS_HM_AC_SWITCH_TO_MAINTENANCE),

    [PRTOS_HM_EV_X86_DOUBLE_FAULT] = TOBIT(PRTOS_HM_AC_IGNORE) | TOBIT(PRTOS_HM_AC_SHUTDOWN) | TOBIT(PRTOS_HM_AC_PARTITION_COLD_RESET) |
                                     TOBIT(PRTOS_HM_AC_PARTITION_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) |
                                     TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_SUSPEND) | TOBIT(PRTOS_HM_AC_PARTITION_HALT) |
                                     TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE) | TOBIT(PRTOS_HM_AC_SWITCH_TO_MAINTENANCE),

    [PRTOS_HM_EV_X86_COPROCESSOR_SEGMENT_OVERRUN] =
        TOBIT(PRTOS_HM_AC_IGNORE) | TOBIT(PRTOS_HM_AC_SHUTDOWN) | TOBIT(PRTOS_HM_AC_PARTITION_COLD_RESET) | TOBIT(PRTOS_HM_AC_PARTITION_WARM_RESET) |
        TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_SUSPEND) | TOBIT(PRTOS_HM_AC_PARTITION_HALT) |
        TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE) | TOBIT(PRTOS_HM_AC_SWITCH_TO_MAINTENANCE),

    [PRTOS_HM_EV_X86_INVALID_TSS] = TOBIT(PRTOS_HM_AC_IGNORE) | TOBIT(PRTOS_HM_AC_SHUTDOWN) | TOBIT(PRTOS_HM_AC_PARTITION_COLD_RESET) |
                                    TOBIT(PRTOS_HM_AC_PARTITION_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) |
                                    TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_SUSPEND) | TOBIT(PRTOS_HM_AC_PARTITION_HALT) |
                                    TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE) | TOBIT(PRTOS_HM_AC_SWITCH_TO_MAINTENANCE),

    [PRTOS_HM_EV_X86_SEGMENT_NOT_PRESENT] = TOBIT(PRTOS_HM_AC_IGNORE) | TOBIT(PRTOS_HM_AC_SHUTDOWN) | TOBIT(PRTOS_HM_AC_PARTITION_COLD_RESET) |
                                            TOBIT(PRTOS_HM_AC_PARTITION_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) |
                                            TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_SUSPEND) | TOBIT(PRTOS_HM_AC_PARTITION_HALT) |
                                            TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE) | TOBIT(PRTOS_HM_AC_SWITCH_TO_MAINTENANCE),

    [PRTOS_HM_EV_X86_STACK_FAULT] = TOBIT(PRTOS_HM_AC_IGNORE) | TOBIT(PRTOS_HM_AC_SHUTDOWN) | TOBIT(PRTOS_HM_AC_PARTITION_COLD_RESET) |
                                    TOBIT(PRTOS_HM_AC_PARTITION_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) |
                                    TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_SUSPEND) | TOBIT(PRTOS_HM_AC_PARTITION_HALT) |
                                    TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE) | TOBIT(PRTOS_HM_AC_SWITCH_TO_MAINTENANCE),

    [PRTOS_HM_EV_X86_GENERAL_PROTECTION] = TOBIT(PRTOS_HM_AC_IGNORE) | TOBIT(PRTOS_HM_AC_SHUTDOWN) | TOBIT(PRTOS_HM_AC_PARTITION_COLD_RESET) |
                                           TOBIT(PRTOS_HM_AC_PARTITION_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) |
                                           TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_SUSPEND) | TOBIT(PRTOS_HM_AC_PARTITION_HALT) |
                                           TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE) | TOBIT(PRTOS_HM_AC_SWITCH_TO_MAINTENANCE),

    [PRTOS_HM_EV_X86_PAGE_FAULT] = TOBIT(PRTOS_HM_AC_IGNORE) | TOBIT(PRTOS_HM_AC_SHUTDOWN) | TOBIT(PRTOS_HM_AC_PARTITION_COLD_RESET) |
                                   TOBIT(PRTOS_HM_AC_PARTITION_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) |
                                   TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_SUSPEND) | TOBIT(PRTOS_HM_AC_PARTITION_HALT) |
                                   TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE) | TOBIT(PRTOS_HM_AC_SWITCH_TO_MAINTENANCE),

    [PRTOS_HM_EV_X86_X87_FPU_ERROR] = TOBIT(PRTOS_HM_AC_IGNORE) | TOBIT(PRTOS_HM_AC_SHUTDOWN) | TOBIT(PRTOS_HM_AC_PARTITION_COLD_RESET) |
                                      TOBIT(PRTOS_HM_AC_PARTITION_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) |
                                      TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_SUSPEND) | TOBIT(PRTOS_HM_AC_PARTITION_HALT) |
                                      TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE) | TOBIT(PRTOS_HM_AC_SWITCH_TO_MAINTENANCE),

    [PRTOS_HM_EV_X86_ALIGNMENT_CHECK] = TOBIT(PRTOS_HM_AC_IGNORE) | TOBIT(PRTOS_HM_AC_SHUTDOWN) | TOBIT(PRTOS_HM_AC_PARTITION_COLD_RESET) |
                                        TOBIT(PRTOS_HM_AC_PARTITION_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) |
                                        TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_SUSPEND) | TOBIT(PRTOS_HM_AC_PARTITION_HALT) |
                                        TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE) | TOBIT(PRTOS_HM_AC_SWITCH_TO_MAINTENANCE),

    [PRTOS_HM_EV_X86_MACHINE_CHECK] = TOBIT(PRTOS_HM_AC_IGNORE) | TOBIT(PRTOS_HM_AC_SHUTDOWN) | TOBIT(PRTOS_HM_AC_PARTITION_COLD_RESET) |
                                      TOBIT(PRTOS_HM_AC_PARTITION_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) |
                                      TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_SUSPEND) | TOBIT(PRTOS_HM_AC_PARTITION_HALT) |
                                      TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE) | TOBIT(PRTOS_HM_AC_SWITCH_TO_MAINTENANCE),

    [PRTOS_HM_EV_X86_SIMD_FLOATING_POINT] = TOBIT(PRTOS_HM_AC_IGNORE) | TOBIT(PRTOS_HM_AC_SHUTDOWN) | TOBIT(PRTOS_HM_AC_PARTITION_COLD_RESET) |
                                            TOBIT(PRTOS_HM_AC_PARTITION_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) |
                                            TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_SUSPEND) | TOBIT(PRTOS_HM_AC_PARTITION_HALT) |
                                            TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE) | TOBIT(PRTOS_HM_AC_SWITCH_TO_MAINTENANCE),
#endif
};

static prtos_u32_t hm_hypervisor_events_and_actions[PRTOS_HM_MAX_EVENTS] = {
    [PRTOS_HM_EV_FATAL_ERROR] = TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT),

    [PRTOS_HM_EV_SYSTEM_ERROR] = TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT),
    [PRTOS_HM_EV_PARTITION_ERROR] = TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT),
    [PRTOS_HM_EV_FP_ERROR] = TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT),

    [PRTOS_HM_EV_MEM_PROTECTION] = TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT),

    [PRTOS_HM_EV_UNEXPECTED_TRAP] = TOBIT(PRTOS_HM_AC_IGNORE) | TOBIT(PRTOS_HM_AC_SHUTDOWN) | TOBIT(PRTOS_HM_AC_PARTITION_COLD_RESET) |
                                    TOBIT(PRTOS_HM_AC_PARTITION_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) |
                                    TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_SUSPEND) | TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) |
                                    TOBIT(PRTOS_HM_AC_SWITCH_TO_MAINTENANCE),

#ifdef CONFIG_x86
    [PRTOS_HM_EV_X86_DIVIDE_ERROR] =
        TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE),

    [PRTOS_HM_EV_X86_DEBUG] =
        TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE),

    [PRTOS_HM_EV_X86_NMI_INTERRUPT] =
        TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE),

    [PRTOS_HM_EV_X86_BREAKPOINT] =
        TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE),

    [PRTOS_HM_EV_X86_OVERFLOW] =
        TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE),

    [PRTOS_HM_EV_X86_BOUND_RANGE_EXCEEDED] =
        TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE),

    [PRTOS_HM_EV_X86_INVALID_OPCODE] =
        TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE),

    [PRTOS_HM_EV_X86_DEVICE_NOT_AVAILABLE] =
        TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE),

    [PRTOS_HM_EV_X86_DOUBLE_FAULT] =
        TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE),

    [PRTOS_HM_EV_X86_COPROCESSOR_SEGMENT_OVERRUN] =
        TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE),

    [PRTOS_HM_EV_X86_INVALID_TSS] =
        TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE),

    [PRTOS_HM_EV_X86_SEGMENT_NOT_PRESENT] =
        TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE),

    [PRTOS_HM_EV_X86_STACK_FAULT] =
        TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE),

    [PRTOS_HM_EV_X86_GENERAL_PROTECTION] =
        TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE),

    [PRTOS_HM_EV_X86_PAGE_FAULT] =
        TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE),

    [PRTOS_HM_EV_X86_X87_FPU_ERROR] =
        TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE),

    [PRTOS_HM_EV_X86_ALIGNMENT_CHECK] =
        TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE),

    [PRTOS_HM_EV_X86_MACHINE_CHECK] =
        TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE),

    [PRTOS_HM_EV_X86_SIMD_FLOATING_POINT] =
        TOBIT(PRTOS_HM_AC_HYPERVISOR_COLD_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_WARM_RESET) | TOBIT(PRTOS_HM_AC_HYPERVISOR_HALT) | TOBIT(PRTOS_HM_AC_PROPAGATE),
#endif
};

static struct prtos_conf_hm_slot default_partition_hm_table[PRTOS_HM_MAX_EVENTS] = {
    /* hm part default conf */
    [PRTOS_HM_EV_FATAL_ERROR] =
        {
            .action = PRTOS_HM_AC_PARTITION_HALT,
            .log = PRTOS_HM_LOG_ENABLED,
        },
    [PRTOS_HM_EV_SYSTEM_ERROR] =
        {
            .action = PRTOS_HM_AC_PARTITION_HALT,
            .log = PRTOS_HM_LOG_ENABLED,
        },
    [PRTOS_HM_EV_PARTITION_ERROR] =
        {
            .action = PRTOS_HM_AC_PARTITION_HALT,
            .log = PRTOS_HM_LOG_ENABLED,
        },
    [PRTOS_HM_EV_FP_ERROR] =
        {
            .action = PRTOS_HM_AC_PARTITION_HALT,
            .log = PRTOS_HM_LOG_ENABLED,
        },

    [PRTOS_HM_EV_MEM_PROTECTION] =
        {
            .action = PRTOS_HM_AC_PARTITION_HALT,
            .log = PRTOS_HM_LOG_ENABLED,
        },
    [PRTOS_HM_EV_UNEXPECTED_TRAP] =
        {
            .action = PRTOS_HM_AC_PARTITION_HALT,
            .log = PRTOS_HM_LOG_ENABLED,
        },

#ifdef CONFIG_x86
    /* hm part default conf x86 */
    [PRTOS_HM_EV_X86_DIVIDE_ERROR] =
        {
            .action = PRTOS_HM_AC_PARTITION_HALT,
            .log = PRTOS_HM_LOG_DISABLED,
        },
    [PRTOS_HM_EV_X86_DEBUG] =
        {
            .action = PRTOS_HM_AC_PARTITION_HALT,
            .log = PRTOS_HM_LOG_DISABLED,
        },
    [PRTOS_HM_EV_X86_NMI_INTERRUPT] =
        {
            .action = PRTOS_HM_AC_PARTITION_HALT,
            .log = PRTOS_HM_LOG_DISABLED,
        },
    [PRTOS_HM_EV_X86_BREAKPOINT] =
        {
            .action = PRTOS_HM_AC_PARTITION_HALT,
            .log = PRTOS_HM_LOG_DISABLED,
        },
    [PRTOS_HM_EV_X86_OVERFLOW] =
        {
            .action = PRTOS_HM_AC_PARTITION_HALT,
            .log = PRTOS_HM_LOG_DISABLED,
        },
    [PRTOS_HM_EV_X86_BOUND_RANGE_EXCEEDED] =
        {
            .action = PRTOS_HM_AC_PARTITION_HALT,
            .log = PRTOS_HM_LOG_DISABLED,
        },
    [PRTOS_HM_EV_X86_INVALID_OPCODE] =
        {
            .action = PRTOS_HM_AC_PARTITION_HALT,
            .log = PRTOS_HM_LOG_DISABLED,
        },
    [PRTOS_HM_EV_X86_DEVICE_NOT_AVAILABLE] =
        {
            .action = PRTOS_HM_AC_PARTITION_HALT,
            .log = PRTOS_HM_LOG_DISABLED,
        },
    [PRTOS_HM_EV_X86_DOUBLE_FAULT] =
        {
            .action = PRTOS_HM_AC_PARTITION_HALT,
            .log = PRTOS_HM_LOG_DISABLED,
        },
    [PRTOS_HM_EV_X86_COPROCESSOR_SEGMENT_OVERRUN] =
        {
            .action = PRTOS_HM_AC_PARTITION_HALT,
            .log = PRTOS_HM_LOG_DISABLED,
        },
    [PRTOS_HM_EV_X86_INVALID_TSS] =
        {
            .action = PRTOS_HM_AC_PARTITION_HALT,
            .log = PRTOS_HM_LOG_DISABLED,
        },
    [PRTOS_HM_EV_X86_SEGMENT_NOT_PRESENT] =
        {
            .action = PRTOS_HM_AC_PARTITION_HALT,
            .log = PRTOS_HM_LOG_DISABLED,
        },
    [PRTOS_HM_EV_X86_STACK_FAULT] =
        {
            .action = PRTOS_HM_AC_PARTITION_HALT,
            .log = PRTOS_HM_LOG_DISABLED,
        },
    [PRTOS_HM_EV_X86_GENERAL_PROTECTION] =
        {
            .action = PRTOS_HM_AC_PARTITION_HALT,
            .log = PRTOS_HM_LOG_DISABLED,
        },
    [PRTOS_HM_EV_X86_PAGE_FAULT] =
        {
            .action = PRTOS_HM_AC_PARTITION_HALT,
            .log = PRTOS_HM_LOG_DISABLED,
        },
    [PRTOS_HM_EV_X86_X87_FPU_ERROR] =
        {
            .action = PRTOS_HM_AC_PARTITION_HALT,
            .log = PRTOS_HM_LOG_DISABLED,
        },
    [PRTOS_HM_EV_X86_ALIGNMENT_CHECK] =
        {
            .action = PRTOS_HM_AC_PARTITION_HALT,
            .log = PRTOS_HM_LOG_DISABLED,
        },
    [PRTOS_HM_EV_X86_MACHINE_CHECK] =
        {
            .action = PRTOS_HM_AC_PARTITION_HALT,
            .log = PRTOS_HM_LOG_DISABLED,
        },
    [PRTOS_HM_EV_X86_SIMD_FLOATING_POINT] =
        {
            .action = PRTOS_HM_AC_PARTITION_HALT,
            .log = PRTOS_HM_LOG_DISABLED,
        },
#endif
};

static struct prtos_conf_hm_slot default_hypervisor_hm_table[PRTOS_HM_MAX_EVENTS] = {
    /* hm prtos hyp default conf */
    [PRTOS_HM_EV_FATAL_ERROR] =
        {
            .action = PRTOS_HM_AC_HYPERVISOR_HALT,
            .log = PRTOS_HM_LOG_ENABLED,
        },
    [PRTOS_HM_EV_SYSTEM_ERROR] =
        {
            .action = PRTOS_HM_AC_HYPERVISOR_HALT,
            .log = PRTOS_HM_LOG_ENABLED,
        },
    [PRTOS_HM_EV_PARTITION_ERROR] =
        {
            .action = PRTOS_HM_AC_HYPERVISOR_HALT,
            .log = PRTOS_HM_LOG_ENABLED,
        },
    [PRTOS_HM_EV_FP_ERROR] =
        {
            .action = PRTOS_HM_AC_HYPERVISOR_HALT,
            .log = PRTOS_HM_LOG_ENABLED,
        },
    [PRTOS_HM_EV_MEM_PROTECTION] =
        {
            .action = PRTOS_HM_AC_HYPERVISOR_HALT,
            .log = PRTOS_HM_LOG_ENABLED,
        },
    [PRTOS_HM_EV_UNEXPECTED_TRAP] =
        {
            .action = PRTOS_HM_AC_HYPERVISOR_HALT,
            .log = PRTOS_HM_LOG_ENABLED,
        },
#ifdef CONFIG_x86
    /* hm prtos hyp default conf x86 */
    [PRTOS_HM_EV_X86_DIVIDE_ERROR] =
        {
            .action = PRTOS_HM_AC_HYPERVISOR_HALT,
            .log = PRTOS_HM_LOG_ENABLED,
        },
    [PRTOS_HM_EV_X86_DEBUG] =
        {
            .action = PRTOS_HM_AC_HYPERVISOR_HALT,
            .log = PRTOS_HM_LOG_ENABLED,
        },
    [PRTOS_HM_EV_X86_NMI_INTERRUPT] =
        {
            .action = PRTOS_HM_AC_HYPERVISOR_HALT,
            .log = PRTOS_HM_LOG_ENABLED,
        },
    [PRTOS_HM_EV_X86_BREAKPOINT] =
        {
            .action = PRTOS_HM_AC_HYPERVISOR_HALT,
            .log = PRTOS_HM_LOG_ENABLED,
        },
    [PRTOS_HM_EV_X86_OVERFLOW] =
        {
            .action = PRTOS_HM_AC_HYPERVISOR_HALT,
            .log = PRTOS_HM_LOG_ENABLED,
        },
    [PRTOS_HM_EV_X86_BOUND_RANGE_EXCEEDED] =
        {
            .action = PRTOS_HM_AC_HYPERVISOR_HALT,
            .log = PRTOS_HM_LOG_ENABLED,
        },
    [PRTOS_HM_EV_X86_INVALID_OPCODE] =
        {
            .action = PRTOS_HM_AC_HYPERVISOR_HALT,
            .log = PRTOS_HM_LOG_ENABLED,
        },
    [PRTOS_HM_EV_X86_DEVICE_NOT_AVAILABLE] =
        {
            .action = PRTOS_HM_AC_HYPERVISOR_HALT,
            .log = PRTOS_HM_LOG_ENABLED,
        },
    [PRTOS_HM_EV_X86_DOUBLE_FAULT] =
        {
            .action = PRTOS_HM_AC_HYPERVISOR_HALT,
            .log = PRTOS_HM_LOG_ENABLED,
        },
    [PRTOS_HM_EV_X86_COPROCESSOR_SEGMENT_OVERRUN] =
        {
            .action = PRTOS_HM_AC_HYPERVISOR_HALT,
            .log = PRTOS_HM_LOG_ENABLED,
        },
    [PRTOS_HM_EV_X86_INVALID_TSS] =
        {
            .action = PRTOS_HM_AC_HYPERVISOR_HALT,
            .log = PRTOS_HM_LOG_ENABLED,
        },
    [PRTOS_HM_EV_X86_SEGMENT_NOT_PRESENT] =
        {
            .action = PRTOS_HM_AC_HYPERVISOR_HALT,
            .log = PRTOS_HM_LOG_ENABLED,
        },
    [PRTOS_HM_EV_X86_STACK_FAULT] =
        {
            .action = PRTOS_HM_AC_HYPERVISOR_HALT,
            .log = PRTOS_HM_LOG_ENABLED,
        },
    [PRTOS_HM_EV_X86_GENERAL_PROTECTION] =
        {
            .action = PRTOS_HM_AC_HYPERVISOR_HALT,
            .log = PRTOS_HM_LOG_ENABLED,
        },
    [PRTOS_HM_EV_X86_PAGE_FAULT] =
        {
            .action = PRTOS_HM_AC_HYPERVISOR_HALT,
            .log = PRTOS_HM_LOG_ENABLED,
        },
    [PRTOS_HM_EV_X86_X87_FPU_ERROR] =
        {
            .action = PRTOS_HM_AC_HYPERVISOR_HALT,
            .log = PRTOS_HM_LOG_ENABLED,
        },
    [PRTOS_HM_EV_X86_ALIGNMENT_CHECK] =
        {
            .action = PRTOS_HM_AC_HYPERVISOR_HALT,
            .log = PRTOS_HM_LOG_ENABLED,
        },
    [PRTOS_HM_EV_X86_MACHINE_CHECK] =
        {
            .action = PRTOS_HM_AC_HYPERVISOR_HALT,
            .log = PRTOS_HM_LOG_ENABLED,
        },
    [PRTOS_HM_EV_X86_SIMD_FLOATING_POINT] =
        {
            .action = PRTOS_HM_AC_HYPERVISOR_HALT,
            .log = PRTOS_HM_LOG_ENABLED,
        },
#endif
};

void setup_default_hyp_hm_actions(struct prtos_conf_hm_slot *hm_table) {
    memcpy(hm_table, default_hypervisor_hm_table, sizeof(struct prtos_conf_hm_slot) * PRTOS_HM_MAX_EVENTS);
}

void setup_default_part_hm_actions(struct prtos_conf_hm_slot *hm_table) {
    memcpy(hm_table, default_partition_hm_table, sizeof(struct prtos_conf_hm_slot) * PRTOS_HM_MAX_EVENTS);
}

void hm_hpv_is_action_permitted_on_event(int event, int action, int line) {
    if (!(hm_hypervisor_events_and_actions[event] & TOBIT(action)))
        line_error(line, "Action \"%s\" on event \"%s\" is not permitted", hm_actions[action], hm_events[event]);
}

void hm_part_is_action_permitted_on_event(int event, int action, int line) {
    if (!(hm_partition_events_and_actions[event] & TOBIT(action)))
        line_error(line, "Action \"%s\" on event \"%s\" is not permitted", hm_actions[action], hm_events[event]);
}

void hm_check_exist_maintenance_plan(void) {
    int e, i, maintenance = 0;
    // Are there any maintenance action?
    for (e = 0; e < PRTOS_HM_MAX_EVENTS; e++)
        if (prtos_conf.hpv.hm_table[e].action == PRTOS_HM_AC_SWITCH_TO_MAINTENANCE) maintenance = 1;

    for (e = 0; e < prtos_conf.num_of_partitions; e++)
        for (i = 0; i < PRTOS_HM_MAX_EVENTS; i++)
            if (prtos_conf_partition_table[e].hm_table[i].action == PRTOS_HM_AC_SWITCH_TO_MAINTENANCE) maintenance = 1;

    if (maintenance)
        // Is there a maintenance plan?
        for (e = 0; e < prtos_conf.hpv.num_of_cpus; e++)
            if (prtos_conf.hpv.cpu_table[e].num_of_sched_cyclic_plans < 2)
                line_error(prtos_conf_line_number.hpv.cpu_table[e].id, "Although required, a maintenance plan is not defined for CPU \"%d\"",
                           prtos_conf.hpv.cpu_table[e].id);
}
